import { Request, Response, NextFunction } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { Logger } from '@/utils/logger';

const logger = new Logger('RequestLogger');

// 扩展Request接口以包含请求ID
declare global {
  namespace Express {
    interface Request {
      requestId?: string;
      startTime?: number;
      user?: {
        id: string;
        username: string;
        [key: string]: any;
      };
    }
  }
}

export const requestLogger = (req: Request, res: Response, next: NextFunction): void => {
  // 生成请求ID
  const requestId = uuidv4();
  req.requestId = requestId;
  req.startTime = Date.now();

  // 设置响应头
  res.setHeader('X-Request-ID', requestId);

  // 记录请求开始
  const requestInfo = {
    requestId,
    method: req.method,
    url: req.originalUrl,
    userAgent: req.get('User-Agent'),
    ip: req.ip,
    contentType: req.get('Content-Type'),
    contentLength: req.get('Content-Length'),
    referer: req.get('Referer'),
    timestamp: new Date().toISOString()
  };

  // 不记录敏感信息
  const sensitiveFields = ['password', 'token', 'api_key', 'secret'];
  const logBody = shouldLogBody(req) ? sanitizeBody(req.body, sensitiveFields) : undefined;

  if (logBody && Object.keys(logBody).length > 0) {
    requestInfo['body'] = logBody;
  }

  logger.info('Request started', requestInfo);

  // 监听响应完成
  const originalSend = res.send;
  const originalJson = res.json;
  let responseBody: any;

  res.send = function(data: any) {
    responseBody = data;
    return originalSend.call(this, data);
  };

  res.json = function(data: any) {
    responseBody = data;
    return originalJson.call(this, data);
  };

  // 响应完成时记录日志
  res.on('finish', () => {
    const endTime = Date.now();
    const duration = req.startTime ? endTime - req.startTime : 0;

    const responseInfo = {
      requestId,
      method: req.method,
      url: req.originalUrl,
      statusCode: res.statusCode,
      duration: `${duration}ms`,
      contentLength: res.get('Content-Length'),
      userId: req.user?.id,
      timestamp: new Date().toISOString()
    };

    // 记录响应体（仅在开发环境或错误时）
    if (shouldLogResponseBody(req, res, responseBody)) {
      const sanitizedResponse = sanitizeResponse(responseBody, sensitiveFields);
      if (sanitizedResponse) {
        responseInfo['response'] = sanitizedResponse;
      }
    }

    // 根据状态码决定日志级别
    if (res.statusCode >= 500) {
      logger.error('Request completed with server error', responseInfo);
    } else if (res.statusCode >= 400) {
      logger.warn('Request completed with client error', responseInfo);
    } else {
      logger.info('Request completed successfully', responseInfo);
    }
  });

  // 处理响应错误
  res.on('error', (error) => {
    const duration = req.startTime ? Date.now() - req.startTime : 0;
    
    logger.error('Response error occurred', {
      requestId,
      method: req.method,
      url: req.originalUrl,
      duration: `${duration}ms`,
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString()
    });
  });

  next();
};

// 判断是否应该记录请求体
function shouldLogBody(req: Request): boolean {
  // 不记录文件上传和大数据请求
  const contentType = req.get('Content-Type') || '';
  
  if (contentType.includes('multipart/form-data')) {
    return false;
  }
  
  if (contentType.includes('application/octet-stream')) {
    return false;
  }

  const contentLength = parseInt(req.get('Content-Length') || '0');
  if (contentLength > 10240) { // 大于10KB不记录
    return false;
  }

  // 敏感端点不记录请求体
  const sensitiveEndpoints = ['/api/v1/auth/login', '/api/v1/auth/register'];
  if (sensitiveEndpoints.includes(req.path)) {
    return false;
  }

  return true;
}

// 判断是否应该记录响应体
function shouldLogResponseBody(req: Request, res: Response, responseBody: any): boolean {
  // 开发环境记录所有响应
  if (process.env.NODE_ENV === 'development') {
    return true;
  }

  // 错误响应总是记录
  if (res.statusCode >= 400) {
    return true;
  }

  // 大响应不记录
  const responseSize = JSON.stringify(responseBody || {}).length;
  if (responseSize > 10240) { // 大于10KB
    return false;
  }

  return false;
}

// 清理敏感信息
function sanitizeBody(body: any, sensitiveFields: string[]): any {
  if (!body || typeof body !== 'object') {
    return body;
  }

  const sanitized = { ...body };
  
  for (const field of sensitiveFields) {
    if (field in sanitized) {
      sanitized[field] = '[REDACTED]';
    }
  }

  return sanitized;
}

// 清理响应中的敏感信息
function sanitizeResponse(responseBody: any, sensitiveFields: string[]): any {
  if (!responseBody) {
    return responseBody;
  }

  try {
    let sanitized;
    
    if (typeof responseBody === 'string') {
      sanitized = JSON.parse(responseBody);
    } else {
      sanitized = { ...responseBody };
    }

    // 递归清理嵌套对象
    const cleanObject = (obj: any): any => {
      if (!obj || typeof obj !== 'object') {
        return obj;
      }

      if (Array.isArray(obj)) {
        return obj.map(item => cleanObject(item));
      }

      const cleaned = { ...obj };
      for (const field of sensitiveFields) {
        if (field in cleaned) {
          cleaned[field] = '[REDACTED]';
        }
      }

      // 递归处理嵌套对象
      for (const key in cleaned) {
        if (typeof cleaned[key] === 'object') {
          cleaned[key] = cleanObject(cleaned[key]);
        }
      }

      return cleaned;
    };

    return cleanObject(sanitized);
  } catch (error) {
    return '[INVALID_JSON]';
  }
}

// 生成访问日志中间件（类似nginx访问日志）
export const accessLogger = (req: Request, res: Response, next: NextFunction): void => {
  res.on('finish', () => {
    const duration = req.startTime ? Date.now() - req.startTime : 0;
    
    // 标准访问日志格式
    const logLine = [
      req.ip,
      '-',
      req.user?.username || '-',
      `[${new Date().toISOString()}]`,
      `"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}"`,
      res.statusCode,
      res.get('Content-Length') || '-',
      `"${req.get('Referer') || '-'}"`,
      `"${req.get('User-Agent') || '-'}"`,
      `${duration}ms`,
      req.requestId || '-'
    ].join(' ');

    logger.info(logLine);
  });

  next();
};